#include "Tilemap.h"
#include "SpriteState.h"



Tilemap::Tilemap(const char *map, int mapWidth, int mapHeight, int tileWidth, int tileHeight)
	: width(mapWidth), height(mapHeight)
{
	Tile::SetWidthAndHeight(tileWidth, tileHeight);

	tiles = new Tile*[mapWidth * mapHeight];
	for (int y = 0; y < mapHeight; y++)
	{
		for (int x = 0; x < mapWidth; x++)
		{
			const int i = y*mapWidth + x;
			switch (map[i])
			{
			case ' ':
				tiles[i] = new Tile(x*tileWidth, y*tileHeight, true, D3DCOLOR_XRGB(255, 255, 255));
				break;
			case '#':
				tiles[i] = new Tile(x*tileWidth, y*tileHeight, false, D3DCOLOR_XRGB(0, 0, 0));
				break;
			default:
				tiles[i] = NULL;
				break;
			}
		}
	}
}


Tilemap::~Tilemap()
{
	for (int i = 0; i < width*height; i++)
	{
		delete tiles[i];
	}
	delete[]tiles;
}

void Tilemap::Draw(D3DGraphics &gfx) const
{
	for (int i = 0; i < width*height; i++)
	{
		tiles[i]->Draw(gfx);
	}
}

void Tilemap::GetCRectsList(CollisionRectF cRect, RectFList &list)
{
	for (int iy = Tile::GetIndexYBiasBottom(cRect.top), iyEnd = Tile::GetIndexYBiasTop(cRect.bottom);
		iy <= iyEnd; iy++)
	{
		for (int ix = Tile::GetIndexXBiasRight(cRect.left), ixEnd = Tile::GetIndexXBiasLeft(cRect.right);
			ix <= ixEnd; ix++)
		{
			if (!GetTile(ix, iy)->IsPassable())
			{
				list.push_back(Tile::GetCRect(ix, iy));
			}
		}
	} 
}

bool Tilemap::GetCRectSingle(CollisionRectF &cRect, CollisionRectF &rectOut)
{
	if (cRect.vx > 0.0f)
	{
		if (cRect.vy < 0.0f)
		{
			for (int iy = Tile::GetIndexYBiasTop(cRect.bottom), iyEnd = Tile::GetIndexYBiasBottom(cRect.top);
				iy >= iyEnd; iy--)
			{
				for (int ix = Tile::GetIndexXBiasRight(cRect.left), ixEnd = Tile::GetIndexXBiasLeft(cRect.right);
					ix <= ixEnd; ix ++)
				{
					if (!GetTile(ix, iy)->IsPassable())
					{
						rectOut = Tile::GetCRect(ix, iy);
						return true;
					}
				}
			}
		}
		else
		{
			for (int iy = Tile::GetIndexYBiasBottom(cRect.top), iyEnd = Tile::GetIndexYBiasTop(cRect.bottom);
				iy <= iyEnd; iy ++)
			{
				for (int ix = Tile::GetIndexXBiasRight(cRect.left), ixEnd = Tile::GetIndexXBiasLeft(cRect.right);
					ix <= ixEnd; ix ++)
				{
					if (!GetTile(ix, iy)->IsPassable())
					{
						rectOut = Tile::GetCRect(ix, iy);
						return true;
					}
				}
			}
		}
	}
	else
	{
		if (cRect.vy < 0.0f)
		{
			for (int iy = Tile::GetIndexYBiasTop(cRect.bottom), iyEnd = Tile::GetIndexYBiasBottom(cRect.top);
				iy >= iyEnd; iy--)
			{
				for (int ix = Tile::GetIndexXBiasLeft(cRect.right), ixEnd = Tile::GetIndexXBiasRight(cRect.left);
					ix >= ixEnd; ix --)
				{
					if (!GetTile(ix, iy)->IsPassable())
					{
						rectOut = Tile::GetCRect(ix, iy);
						return true;
					}
				}
			}
		}
		else
		{
			for (int iy = Tile::GetIndexYBiasBottom(cRect.top), iyEnd = Tile::GetIndexYBiasTop(cRect.bottom);
				iy <= iyEnd; iy ++)
			{
				for (int ix = Tile::GetIndexXBiasLeft(cRect.right), ixEnd = Tile::GetIndexXBiasRight(cRect.left);
					ix >= ixEnd; ix--)
				{
					if (!GetTile(ix, iy)->IsPassable())
					{
						rectOut = Tile::GetCRect(ix, iy);
						return true;
					}
				}
			}
		}
	}

	return false;
}

void Tilemap::DoCollision(Sprite &s)
{
	CollisionRectF rect;
	while (GetCRectSingle(s.GetCRect(), rect))
	{
		s.GetState().OnCollision(rect);
	}
}

void Tilemap:: DoSupport(Sprite &s)
{ 
	CollisionRectF cRect = s.GetCRect();
	int iy = Tile::GetIndexYBiasBottom(cRect.bottom);

	for (int ix = Tile::GetIndexXBiasRight(cRect.left), ixEnd = Tile::GetIndexXBiasLeft(cRect.right);
		ix <= ixEnd; ix++)
	{
		if (!GetTile(ix, iy)->IsPassable())// && Tile::GetCRect(ix, iy).top == cRect.bottom)
		{
			return;
		}
	}
	s.GetState().OnUnsupported();
} 